# Copyright (c) 2022 Presto Labs Pte. Ltd.
# Author: fengyang

import math
import requests
from coin2.exchange.product_info import ProductInfoDefault
from coin2.exchange.symbology import SymbologyInfo
import datetime
import re

def week_expiration(trading_datetime):
  date = trading_datetime.date()
  if date.weekday() < 4:
    expiry_date = date + datetime.timedelta(days=(4 - date.weekday()))
  elif date.weekday() > 4:
    expiry_date = date + datetime.timedelta(days=(4 - date.weekday() + 7))
  elif trading_datetime.hour < 8:
    expiry_date = date
  elif trading_datetime.hour >= 8:
    expiry_date = date + datetime.timedelta(days=7)

  return datetime.datetime(
      year=expiry_date.year,
      month=expiry_date.month,
      day=expiry_date.day,
      hour=8)


def next_week_expiration(trading_datetime):
  return week_expiration(week_expiration(trading_datetime) + datetime.timedelta(days=1))


def last_friday_of_month(year, month):
  if month == 12:
    next_month = datetime.datetime(
        year=year + 1,
        month=1,
        day=1,
        hour=8)
  else:
    next_month = datetime.datetime(
        year=year,
        month=month + 1,
        day=1,
        hour=8)
  this_month_last_day = next_month - datetime.timedelta(days=1)
  day = this_month_last_day
  while True:
    if day.weekday() == 4:
      break
    day = day - datetime.timedelta(days=1)
  return day


def quarter_expiration(trading_datetime):
  quarter_month = ((trading_datetime.month // 4 + 1) % 5) * 3
  this_quater_friday = last_friday_of_month(
      trading_datetime.year, quarter_month)
  if (trading_datetime > this_quater_friday):
    if quarter_month == 12:
      return last_friday_of_month(trading_datetime.year + 1, 3)
    else:
      return last_friday_of_month(trading_datetime.year, quarter_month + 3)
  else:
    return this_quater_friday


def next_quarter_expiration(trading_datetime):
  return quarter_expiration(quarter_expiration(trading_datetime) + datetime.timedelta(days=1))


def nnext_quarter_expiration(trading_datetime):
  return quarter_expiration(next_quarter_expiration(trading_datetime) + datetime.timedelta(days=1))


def to_expire(native_symbol, expire_to_norm):
  symbol_comps = native_symbol.split('_')
  if len(symbol_comps) == 2:
    return "PERPETUAL"
  expore_date_str = symbol_comps[2]
  date_object = datetime.datetime.strptime(expore_date_str, '%y%m%d')
  for item in expire_to_norm:
    if date_object <= item:
      date_object = item
      break
  return expire_to_norm[date_object]

asset_multiplier_base_list = ["10000LADYS", "10000AIDOGE", "1000XEC"]


def generate():
  mea = 'Futures.Bitget.v1'
  me = 'Futures.Bitget'
  default = ProductInfoDefault()
  symbol_info = SymbologyInfo()

  now = datetime.datetime.utcnow()
  quarter = quarter_expiration(now)
  next_quarter = next_quarter_expiration(now)
  nnext_quarter = nnext_quarter_expiration(now)

  expire_to_norm = {
      quarter: "QUARTER",
      next_quarter: "NEXT_QUARTER",
      nnext_quarter: "NNEXT_QUARTER"
  }

  product_types = ["umcbl", "dmcbl", "cmcbl"]
  pis = []
  for product_type in product_types:
    url = "https://api.bitget.com/api/mix/v1/market/contracts?productType=" + product_type
    data = requests.get(url).json()['data']

    for info in data:
      native_symbol = info['symbol']
      symbol_comps = native_symbol.split('_')
      assert len(symbol_comps) >= 2
      market = symbol_comps[1]
      native_base = info['baseCoin']

      if len(symbol_comps) == 3:
        symbol_date = datetime.datetime.strptime(symbol_comps[2], "%y%m%d")
        if now > symbol_date:
          continue

      if market == 'CMCBL':
        native_quote = "USDC"
      else:
        native_quote = info['quoteCoin']

      inverse = False
      if (market == "DMCBL"):
        inverse = True

      base = symbol_info.native_to_norm_currency(mea, native_base)
      quote = symbol_info.native_to_norm_currency(mea, native_quote)
      expire = to_expire(native_symbol, expire_to_norm)
      symbol = "%s-%s" % (base, quote) + "." + expire
      pi = dict(
          symbol=symbol,
          base=base,
          quote=quote,
          native_symbol=native_symbol,
          native_base=native_base,
          native_quote=native_quote,
          price_ticksize=int(info['priceEndStep']) / pow(10, int(info['pricePlace'])),
          qty_ticksize=float(info["sizeMultiplier"]),
          is_inverse=inverse,
          contract_value=1
      )
      
      if base in asset_multiplier_base_list:
        regex = "^[0-9]{2,}"
        result = re.search(regex, base)
        asset_multiplier = float(result.group(0))
        asset = base[len(result.group(0)):]
        pi["asset"] = asset
        pi["asset_multiplier"] = asset_multiplier


      pi = {**pi, **default.product_info(me, symbol)}
      pis.append(pi)

  pis = sorted(pis, key=lambda x: x['symbol'])
  return pis


def gen_coin1_constants():
  data = generate()
  data = convert_coin1_constants(data)
  return data


def convert_coin1_constants(data):
  symbol_list = [info['native_symbol'] for info in data]
  quote_currency_list = list({info['native_quote'] for info in data})
  base_currency_list = list({info['native_base'] for info in data})
  currency_list = base_currency_list + quote_currency_list
  return {
      'symbol_list': symbol_list,
      'currency_list': currency_list,
      'quote_currency_list': quote_currency_list,
  }


if __name__ == "__main__":
  import json
  print(json.dumps(generate(), indent=2))


# https://www.bitget.com/spot/BTCUSDT?type=spot
